//
//  PlayerViewController.swift
//  GhostWorld
//
//  Created by Kam on 2018/4/2.
//  Copyright © 2018 LKGood. All rights reserved.
//

import UIKit
import AlamofireImage
import AVFoundation
import PKHUD

class PlayerViewController: BaseViewController {

  // MARK: - IBOutlets
  
  @IBOutlet private weak var sliderView: SliderView!
  @IBOutlet private weak var coverImageView: UIImageView!
  @IBOutlet private weak var coverShadowView: UIView!
  @IBOutlet private weak var albumNameLabel: UILabel!
  @IBOutlet private weak var audioNameLabel: UILabel!
  @IBOutlet private weak var writerNameLabel: UILabel!
  @IBOutlet private weak var readerNameLabel: UILabel!
  @IBOutlet private weak var currentTimeLabel: UILabel!
  @IBOutlet private weak var totalTimeLabel: UILabel!
  @IBOutlet private weak var draggingTipView: UIView!
  @IBOutlet private weak var draggingTipLabel: UILabel!
  @IBOutlet private weak var draggingTipViewCenterConstraint: NSLayoutConstraint!
  @IBOutlet private weak var buttonView: UIView!
  @IBOutlet private weak var rateView: RateView!
  
  @IBOutlet private weak var playPauseButton: UIButton!
  @IBOutlet private weak var moreButton: UIButton!
  @IBOutlet private weak var prevButton: UIButton!
  @IBOutlet private weak var backwardButton: UIButton!
  @IBOutlet private weak var forwardButton: UIButton!
  @IBOutlet private weak var nextButton: UIButton!
  @IBOutlet private weak var sleepView: UIView!
  @IBOutlet private weak var sleepLabel: UILabel!
  
  // MARK: - Private vars
  
  private var currentAudioDurationSeconds: Double = 0.0
  private var currentAudioAlbumImage: UIImage?
  
  private var favBarButtonItem: UIBarButtonItem?
  private var favAudio: FavAudio?
  
  private var playerMoreViewController: PlayerMoreViewController?
  
  // MARK: - Private methods
  
  private func prepareUI() {
    // slider
    sliderView.delegate = self
    if let audio = NowPlayingManager.shared.audio {
      sliderView.progress = audio.getPlayProgress()
    }
    
    // buttons
    resetButtonUIForPlayingState()
    
    // cover image view
    coverImageView.clipsToBounds = true
    coverImageView.layer.cornerRadius = 10
    coverShadowView.backgroundColor = UIColor(fromRGB: 0x222222)
    coverShadowView.layer.cornerRadius = coverImageView.layer.cornerRadius
    coverShadowView.layer.masksToBounds = false
    coverShadowView.layer.shadowColor = UIColor.black.cgColor
    coverShadowView.layer.shadowOpacity = 0.7
    coverShadowView.layer.shadowOffset = CGSize(width: 0, height: 0)
    coverShadowView.layer.shadowRadius = 10
    coverShadowView.layer.shouldRasterize = true
    
    // info
    resetUIForPlaying()
    
    // dragging tip label
    draggingTipView.clipsToBounds = true
    draggingTipView.layer.cornerRadius = 2
    draggingTipView.layer.cornerRadius = draggingTipView.layer.cornerRadius
    draggingTipView.layer.masksToBounds = false
    draggingTipView.layer.shadowColor = UIColor.black.cgColor
    draggingTipView.layer.shadowOpacity = 0.7
    draggingTipView.layer.shadowOffset = CGSize(width: 0, height: 0)
    draggingTipView.layer.shadowRadius = 10
    draggingTipView.alpha = 0
    
    // auto sleep label
    switch NowPlayingManager.shared.autoSleepType {
    case .disabled:
      sleepLabel.text = ""
    case .afterCurrentAudio:
      sleepLabel.text = "当前"
    case .afterSeconds:
      sleepLabel.text = String.formatTimeInterval(Int(NowPlayingManager.shared.autoSleepLeftSeconds))
    }
    
//    sliderView.alpha = 0
//    currentTimeLabel.alpha = 0
//    totalTimeLabel.alpha = 0
//    buttonView.alpha = 0
//    rateView.alpha = 0
    
    rateView.delegate = self
  }
  
  private func resetUIForPlaying() {
    if let album = NowPlayingManager.shared.album,
      let audio = NowPlayingManager.shared.audio {
      
      if let url = album.cover.getURL(size: .original) {
        coverImageView.af_setImage(withURL: url) { response in
          if let data = response.data, let image = UIImage(data: data) {
            self.currentAudioAlbumImage = image
          }
        }
      }
      albumNameLabel.text = album.name
      audioNameLabel.text = audio.name
      
      if let count = album.writers?.count, count > 0 {
        writerNameLabel.text = album.writers!.map{ ($0 as! Writer).name! }.joined(separator: ",")
      } else {
        writerNameLabel.text = "未知"
      }
      
      if let count = album.readers?.count, count > 0 {
        readerNameLabel.text = album.readers!.map{ ($0 as! Reader).name! }.joined(separator: ",")
      } else {
        readerNameLabel.text = "未知"
      }
    }
  }
  
  private func prepareFavBarButtonItem() {
    if UserManager.shared.currentUser != nil,
      let audioID = NowPlayingManager.shared.audio?.id {
      do {
        favAudio = try FavAudio.get(audioID: Int(audioID))
        let imageName = (favAudio == nil ? "FavItem" : "FavItemHL")
        resetFavBarButtonItem(imageName: imageName)
      } catch let error {
        loggingPrint(error)
        navigationItem.rightBarButtonItem = nil
      }
    } else {
      navigationItem.rightBarButtonItem = nil
    }
  }
  
  private func resetFavBarButtonItem(imageName: String) {
    favBarButtonItem = UIBarButtonItem (
      image: UIImage(named: imageName),
      style: .plain,
      target: self,
      action: #selector(addToFav)
    )
    navigationItem.rightBarButtonItem = favBarButtonItem
  }
  
  @objc private func addToFav() {
    if UserManager.shared.currentUser != nil {
      if favAudio == nil {
        // add to fav
        if let audioIdentifier = NowPlayingManager.shared.audio?.id {
          if let favAudio = FavAudio.add(audioID: Int(audioIdentifier)) {
            self.favAudio = favAudio
            resetFavBarButtonItem(imageName: "FavItemHL")
            HUD.flash(.labeledSuccess(title: "声音已收藏", subtitle: nil), delay: 1.5)
            return
          }
        }
        HUD.flash(.labeledError(title: "声音收藏失败", subtitle: nil), delay: 1.5)
      } else {
        // remove from fav
        do {
          try FavAudio.remove(favAudio!)
          resetFavBarButtonItem(imageName: "FavItem")
          self.favAudio = nil
          HUD.flash(.labeledSuccess(title: "声音已取消收藏", subtitle: nil), delay: 1.5)
        } catch {
          HUD.flash(.labeledError(title: "取消声音收藏失败", subtitle: nil), delay: 1.5)
        }
      }
    }
  }
    
  private func resetButtonUIForPlayingState() {
    var imageName = "PlayerPlayButton"
    if PlayCore.shared.isPlaying {
      imageName = "PlayerPauseButton"
    }
    let image = UIImage(named: imageName)
    playPauseButton.setImage(image, for: .normal)
    
    prepareFavBarButtonItem()
  }
  
  private func resetButtonUIForNextPrevState() {
    prevButton.isEnabled = NowPlayingManager.shared.canPlayPrevAuidoInList
    nextButton.isEnabled = NowPlayingManager.shared.canPlayNextAuidoInList
  }
  
  private func dismissSelf() {
    if let navigationController = navigationController as? BaseNavigationController {
      navigationController.dismissDelegate?.dismiss(navigationController: navigationController, completion: nil)
    }
  }
  
  private func addNotifications() {
    NotificationCenter.default.addObserver(self, selector: #selector(handlePlayPrevNextAudio), name: .nowPlayingMediaInfoChanged, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(finishedPlayingList), name: .finishedAudioPlayingInList, object: nil)
    
    NotificationCenter.default.addObserver(self, selector: #selector(autoSleepCountDidChange), name: .autoSleepCountDidChange, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(autoSleepDidEncountered), name: .autoSleepDidEncountered, object: nil)
    
    NotificationCenter.default.addObserver(self, selector: #selector(popAddPlaylistViewController), name: .audioDidAddedToPlaylist, object: nil)
  }
  
  @objc private func handlePlayPrevNextAudio() {
    resetUIForPlaying()
    resetButtonUIForPlayingState()
    resetButtonUIForNextPrevState()
  }
  
  @objc private func finishedPlayingList() {
    dismissSelf()
  }
  
  @objc private func autoSleepDidEncountered() {
    resetButtonUIForPlayingState()
    sleepLabel.text = ""
  }
  
  @objc private func autoSleepCountDidChange() {
    sleepLabel.text = String.formatTimeInterval(Int(NowPlayingManager.shared.autoSleepLeftSeconds))
  }
  
  @objc private func popAddPlaylistViewController() {
    navigationController?.popViewController(animated: true)
  }
  
  private func loadAudioRate() {
    AudioRateManager.shared.loadRate(audio: NowPlayingManager.shared.audio!) { rate in
      self.rateView.set(rate: rate)
    }
  }
  
  // MARK: - Public vars
  
  
  // MARK: - Lifecycle
  
  override func viewDidLoad() {
    super.viewDidLoad()
    
    addNotifications()
    prepareUI()
    resetButtonUIForNextPrevState()
    loadAudioRate()
  }
  
  override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    
    PlayCore.shared.progressDelegate = self
    PlayCore.shared.playbackDelegate = self
    
    prepareFavBarButtonItem()
  }
  
  override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "ShowPlayerMoreSegue" {
      let playerMoreViewController = segue.destination as! PlayerMoreViewController
      playerMoreViewController.delegate = self
      playerMoreViewController.initialFrame = moreButton.convert(moreButton.frame, to: view)
    } else if segue.identifier == "ShowAddToPlaylistSegue" {
      let step2ViewController = segue.destination as! AddToPlayListStep2ViewController
      step2ViewController.selectedAudios = [NowPlayingManager.shared.audio!]
    }
  }
  
  override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
  }
  
  deinit {
    NotificationCenter.default.removeObserver(self)
  }
  
  // MARK: - IBActions
  
  @IBAction func close(_ sender: UIBarButtonItem) {
    dismissSelf()
  }
  
  @IBAction func playPauseButtonTapped() {
    PlayCore.shared.playPause()
  }
  
  @IBAction func backward15Seconds() {
    PlayCore.shared.skipBackward15Seconds()
  }
  
  @IBAction func foreward15Seconds() {
    PlayCore.shared.skipForward15Seconds()
  }
  
  @IBAction func playPrev() {
    if NowPlayingManager.shared.canPlayPrevAuidoInList {
      NowPlayingManager.shared.playPrevAudioInList()
      resetButtonUIForNextPrevState()
      loadAudioRate()
    }
  }
  
  @IBAction func playNext() {
    if NowPlayingManager.shared.canPlayNextAuidoInList {
      NowPlayingManager.shared.playNextAudioInList()
      resetButtonUIForNextPrevState()
      loadAudioRate()
    }
  }
  
  @IBAction func setSleepTime() {
    let alert = UIAlertController(title: "停止播放", message: nil, preferredStyle: .actionSheet)
    
    let afterCurrentAudioAction = UIAlertAction (
      title: "播放完当前声音",
      style: .default) { _ in
        NowPlayingManager.shared.set(autoSleepType: .afterCurrentAudio)
        self.sleepLabel.text = "当前"
    }
    alert.addAction(afterCurrentAudioAction)
    
    let after10MinsAction = UIAlertAction (
      title: "10分钟后",
      style: .default) { _ in
        NowPlayingManager.shared.set(autoSleepType: .afterSeconds(10 * 60))
        self.sleepLabel.text = String.formatTimeInterval(10 * 60)
    }
    alert.addAction(after10MinsAction)
    
    let after30MinsAction = UIAlertAction (
      title: "半小时后",
      style: .default) { _ in
        NowPlayingManager.shared.set(autoSleepType: .afterSeconds(30 * 60))
        self.sleepLabel.text = String.formatTimeInterval(30 * 60)
    }
    alert.addAction(after30MinsAction)
    
    let after1HourAction = UIAlertAction (
      title: "1小时后",
      style: .default) { _ in
        NowPlayingManager.shared.set(autoSleepType: .afterSeconds(60 * 60))
        self.sleepLabel.text = String.formatTimeInterval(60 * 60)
    }
    alert.addAction(after1HourAction)
    
    let after2HoursAction = UIAlertAction (
      title: "2小时后",
      style: .default) { _ in
        NowPlayingManager.shared.set(autoSleepType: .afterSeconds(120 * 60))
        self.sleepLabel.text = String.formatTimeInterval(120 * 60)
    }
    alert.addAction(after2HoursAction)
    
    let cancelAction = UIAlertAction (
      title: "不开启",
      style: .cancel) { _ in
        NowPlayingManager.shared.set(autoSleepType: .disabled)
        self.sleepLabel.text = ""
    }
    alert.addAction(cancelAction)
    
    if let popoverController = alert.popoverPresentationController {
      popoverController.sourceView = sleepView
      popoverController.sourceRect = sleepView.bounds
    }
    present(alert, animated: true, completion: nil)
  }
  
  @IBAction func showMore() {
    performSegue(withIdentifier: "ShowPlayerMoreSegue", sender: nil)
  }
  
  // MARK: - Public methods
  

}

// MARK: - SliderViewDelegate

extension PlayerViewController: SliderViewDelegate {
  func sliderView(_ sliderView: SliderView, draggingProgress: Float) {
    // display and re-position dragging tip view
    let constant = CGFloat(draggingProgress) * sliderView.width - sliderView.width / 2
    draggingTipViewCenterConstraint.constant = constant
    
    let draggingSeconds = Float(currentAudioDurationSeconds) * draggingProgress
    draggingTipLabel.text = String.formatTimeInterval(Int(draggingSeconds))
    
    if draggingTipView.alpha == 0 {
      UIView.animate(withDuration: 0.3) {
        self.draggingTipView.alpha = 1
      }
    }
  }
  
  func sliderView(_ sliderView: SliderView, didEndTouchWithProgress: Float) {
    PlayCore.shared.seek(toProgress: didEndTouchWithProgress)
    
    // hide dragging tip view
    UIView.animate(withDuration: 0.3) {
      self.draggingTipView.alpha = 0
    }
  }
}

// MARK: - PlayCorePlaybackDelegate

extension PlayerViewController: PlayCorePlaybackDelegate {
  func didStartPlaying() {
    loggingPrint("play")
    resetButtonUIForPlayingState()
  }
  
  func didPausePlaying() {
    loggingPrint("pause")
    resetButtonUIForPlayingState()
  }
  
  func didFinishPlaying() {
    loggingPrint("finish")
    resetButtonUIForPlayingState()
  }
}

// MARK: - PlayCoreProgressDelegate

extension PlayerViewController: PlayCoreProgressDelegate {
  func trackPlayingProgress(duration: Double, time: Double, percentage: Float) {
    currentAudioDurationSeconds = duration
    currentTimeLabel.text = String.formatTimeInterval(Int(time < duration ? time : duration))
    totalTimeLabel.text = String.formatTimeInterval(Int(duration))
    sliderView.progress = percentage
  }
  
  func trackCachingProgress(bytesDownloaded: Int, bytesExpected: Int) {
    sliderView.cacheProgress = Float(bytesDownloaded) / Float(bytesExpected)
  }
}

// MARK: - PlayerMoreViewControllerDelegate

extension PlayerViewController: PlayerMoreViewControllerDelegate {
  func dismissPlayerMoreViewController(action: PlayerMoreAction) {
    dismiss(animated: true) {
      switch action {
      case .displayMoreAudiosOfReader:
        loggingPrint("displayMoreAudiosOfReader")
      case .displayMoreAudiosOfWriter:
        loggingPrint("displayMoreAudiosOfWriter")
      case .displayAudioList:
        self.performSegue(withIdentifier: "ShowPlayerListSegue", sender: nil)
      case .addToPlaylist:
        if NowPlayingManager.shared.audio != nil {
          self.performSegue(withIdentifier: "ShowAddToPlaylistSegue", sender: nil)
        }
      case .share:
        loggingPrint("share")
      default:
        break
      }
    }
  }
}

// MARK: - RateViewDelegate

extension PlayerViewController: RateViewDelegate {
  func rate() {
    if let currentUser = UserManager.shared.currentUser {
      
      func send(rate: Int) {
        let body = ["rate": rate]
        API.shared.requestAPI (
          APIURLStrings.sendAudioRate(audioID: Int(NowPlayingManager.shared.audio!.id)),
          method: .post,
          body: body,
          header: API.shared.memeberHeader,
          successCallback: { json in
            loggingPrint(json["message"].stringValue)
            self.loadAudioRate()
        }) { (message, code) in
          loggingPrint("\(message), \(code)")
          self.loadAudioRate()
        }
      }
      
      let alert = UIAlertController(title: "您的评分", message: nil, preferredStyle: .actionSheet)
      
      for index in 1...5 {
        let rateAction = UIAlertAction (
          title: Array(1...index).reduce("") { (result, n) -> String in result + "★" },
          style: .default) { _ in
            send(rate: index)
        }
        alert.addAction(rateAction)
      }
      
      let cancelAction = UIAlertAction (
        title: "关闭",
        style: .default) { _ in
      }
      alert.addAction(cancelAction)
      
      if let popoverController = alert.popoverPresentationController {
        popoverController.sourceView = sleepView
        popoverController.sourceRect = sleepView.bounds
      }
      present(alert, animated: true, completion: nil)
    }
  }
}
